require("plugin")
require("jabber")

plugin.messaging = {
	new = function(p)
		local self = {
			plugin = p,
			buddies = common.getConfig("plugin.messaging.buddies"),
			storeFile = common.getUserPath("messaging_store.lua"),
			messages = {}
		}
		setmetatable(self, { __index = plugin.messaging })
		if not self:jabberOpen() then return nil end
		self:loadMessages()
		return self
	end,
	
	activate = function(self)
		self:showPage()
	end,
	
	destroy = function(self)
		self:jabberClose()
	end,
	
	controlEvent = function(self, event)
		if event == "back" then
			self.plugin.stoicheia:showStartPage()
			return
		end
		if event == "send" then
			self.plugin.stoicheia.gui.pagewin:exec("getValue(\"message\");")
			return
		end
	end,
	
	pageEvent = function(self, event, arg)
		if event == "CLICKED" then
			self.currentBuddy = self.buddies[tonumber(arg)]
			self:refreshBuddy()
			return
		end
		if event == "VALUE" then
			local name, value = unpack(arg:split(":"))
			if name == "message" then
				if value == nil then value = "" end
				value = value:trim()
				if value ~= "" then
					if self.currentBuddy == nil then
						util.sound("error")
					else
						local message = common.urlDecode(value)
						if self:jabberSend(self.currentBuddy.jid, message) then
							self:writeMessage(nil, self.currentBuddy.jid, nil, message)
							self.plugin.stoicheia.gui.pagewin:exec("setValue(\"message\", \"\");")
							util.sound("send")
							self:refreshMessages()
						end
					end
				end
				self.plugin.stoicheia:hiliteControlRaw("send", false)
			end
			return
		end
	end,
	
	pageReady = function(self, url)
		if url:indexof("messaging_list") then return end
		self:refreshBuddy()
		self:refreshMessages()
		self:refreshPresence()
	end,
	
	timerEvent = function(self)
		if jabber.isopen() then
			jabber.yield(10)
		end
	end,
	
	hiliteControl = function(self, name, on)
		if name == "send" then return on end
		return true
	end,
	
	showPage = function(self)
		self.plugin.stoicheia:showPage("messaging", function(event, f)
			if event ~= "html" then return end
			
			local gap = 20
			local clh = (common.getConfig("screen.clock.radius") + common.getConfig("screen.clock.gap")) * 2
			
			local l = layout.new("*", gap .. ",50%," .. gap .. ",50%," .. gap)
			l:size(self.plugin.stoicheia:getScreenSize())
			l:set("2:1", function(loc, x, y, w, h)
				local l2 = layout.new((self.plugin.stoicheia.controlHeight + gap) .. ",40%," .. (f.fontSize + (2 * gap)) .. ",60%," .. gap, "*")
				l2:size(w, h)
				l2:set("1:2", function(loc, x2, y2, w2, h2)
					f:beginList(x + x2, y + y2, w2, h2)
					for i, buddy in pairs(self.buddies) do
						f:renderListItem(buddy.alias, i, 0, "buddy_" .. i)
					end
					f:endList()
				end)
				l2:set("1:3", function(loc, x2, y2, w2, h2)
					f:renderFormLabel("", nil, x + x2, y + y2, w2, "recipient", false)
				end)
				l2:set("1:4", function(loc, x2, y2, w2, h2)
					f:renderText("message", x + x2, y + y2, w2, h2, "", true)
				end)
				l2:render()
			end)
			l:set("4:1", function(loc, x, y, w, h)
				local l2 = layout.new(clh .. ",*," .. (2 * gap), "*")
				l2:size(w, h)
				l2:set("1:2", function(loc, x2, y2, w2, h2)
					f:renderFrame(x + x2, y + y2, w2, h2, "messages", "about:blank")
				end)
				l2:render()
			end)
			l:render()
		end)
		self.plugin.stoicheia:setControls(true, "back", "send")
	end,
	
	jabberOpen = function(self)
		if jabber.isopen() then return false end
		log("plugin.messaging", "Opening jabber")
		local user = common.getConfig("plugin.messaging.user")
		local pass = common.getConfig("plugin.messaging.pass")
		local server = common.getConfig("plugin.messaging.server")
		local port = common.getConfig("plugin.messaging.port")
		if not user or not pass or not server or not port then
			logerr("messaging", "Necessary Jabber connect values are not specified in user config file ~/.stoicheia/config.lua - please edit this file and insert correct values.")
			return false
		end
		if not jabber.open(user, pass, server, port) then return false end
		jabber.dispatcher = function(_type, ...)
			if _type == "message" then
				self:jabberMessage(...)
				return
			end
			if _type == "presence" then
				self:jabberPresence(...)
				return
			end
			if _type == "connection" then
				log("plugin.messaging", "Jabber connection event: %s", table.join({ ... }, ", "))
				return
			end
			log("plugin.messaging", "Unknown jabber event `%s'", _type)
		end
		jabber.yield(1000)
		log("plugin.messaging", "Jabber opened")
		return true
	end,
	
	jabberClose = function(self)
		if not jabber.isopen() then return false end
		jabber.dispatcher = nil
		jabber.close()
		return true
	end,
	
	jabberSend = function(self, to, subject, body)
		log("plugin.messaging", "Sending message to %s", to)
		local ok = try(function(err)
			logerr("plugin.messaging", "Cannot send message to %s: %s", to, err)
			util.sound("error", true)
		end, jabber.send, to, subject, body)
		return ok
	end,
	
	jabberMessage = function(self, from, subject, body)
		log("plugin.messaging", "Received message from `%s' (Subject: %s): %s", from, subject, body)
		self:writeMessage(from, nil, subject, body)
		self:refreshMessages()
		util.sound("receive", true)
	end,
	
	jabberPresence = function(self, jid, status)
		log("plugin.messaging", "Received presence of `%s': %s", jid, status)
		for i, buddy in pairs(self.buddies) do
			if self:stripJidResource(buddy.jid) == self:stripJidResource(jid) then
				buddy.presence = status
			end
		end
		self:refreshPresence()
	end,
	
	stripJidResource = function(self, jid)
		if jid == nil then return nil end
		return string.gsub(jid, "/.*$", "")
	end,
	
	writeMessage = function(self, from, to, subject, body)
		local message = {
			time = os.time(),
			from = from,
			to = to,
			subject = subject,
			body = body
		}
		self.messages[#(self.messages) + 1] = message
		local stream = io.open(self.storeFile, "a+")
		stream:write("MESSAGE(")
		dump(message, function(line) stream:write(line, "\n") end)
		stream:write(")\n\n")
		stream:flush()
		stream:close()
	end,
	
	loadMessages = function(self)
		self.messages = {}
		if util.exists(self.storeFile) then
			MESSAGE = function(message)
				self.messages[#(self.messages) + 1] = message
			end
			dofile(self.storeFile)
			MESSAGE = nil
			return true
		else
			return false
		end
	end,
	
	refreshBuddy = function(self)
		local recipient
		if self.currentBuddy ~= nil then
			recipient = string.format("%s: %s", common.getResource("recipient"), self.currentBuddy.alias)
		else
			recipient = common.getResource("unknown_recipient")
		end
		self.plugin.stoicheia.gui.pagewin:exec(string.format("setText(\"recipient\", \"%s\");", recipient))
	end,
	
	refreshPresence = function(self)
		if not self.plugin.stoicheia.gui then return end
		for i, buddy in pairs(self.buddies) do
			local text = buddy.alias
			if not buddy.presence then buddy.presence = "unavailable" end
			local presence = common.getResource("presence." .. buddy.presence)
			text = string.format("%s (%s)", text, presence)
			self.plugin.stoicheia.gui.pagewin:exec(string.format("setText(\"buddy_%d\", \"%s\");", i, text))
			local online = (buddy.presence == "available") or (buddy.presence == "chat")
			local css  = "list-item smallfont"
			if online then css = css .. " clickable" end
			self.plugin.stoicheia.gui.pagewin:exec(string.format("setClass(\"buddy_%d\", \"%s\");", i, css))
		end
	end,
	
	getBuddy = function(self, jid)
		for n, buddy in pairs(self.buddies) do
			if buddy.jid == jid then return buddy end
		end
		for n, buddy in pairs(self.buddies) do
			if self:stripJidResource(buddy.jid) == self:stripJidResource(jid) then return buddy end
		end
		return nil
	end,
	
	refreshMessages = function(self)
		local max = common.getConfig("plugin.messaging.visibleMessages")
		local total = #(self.messages)
		local first = total - max + 1
		if first < 1 then first = 1 end
		local f = form.new("messaging_list")
		f.r:xmlHeader("UTF-8")
		f.r:htmlBegin()
		f.r:beginl("head")
		f.r:beginl("style")
		f.r:cssSheet(f:getCommonCss())
		f.r:cssSheet({
			[".message"] = {
				["border-bottom"] = "5px solid #ffffff",
				padding = "10px 0px"
			},
			[".message-header"] = {},
			[".message-body"] = {
				["padding-top"] = "10px"
			},
		})
		f.r:endl("style")
		f.r:endl("head")
		f.r:beginl("body")
		f.r:htmlDivBegin("messages smallfont")
		for i = first, total do
			local message = self.messages[i]
			local from = message.from ~= nil
			local jid
			if from then jid = message.from else jid = message.to end
			assert(jid, "JID is nil")
			local buddy = self:getBuddy(jid)
			local alias 
			if buddy then alias = buddy.alias end
			if alias == nil then alias = jid end
			local color
			if buddy then color = buddy.color end
			if color == nil then color = "#ffffff" end
			local function header(name, value)
				if value == nil or value == "" then return end
				f.r:htmlDivBegin("message-header")
				f.r:pe(string.format("%s: %s", common.getResource("messaging." .. name), value))
				f.r:htmlDivEnd("message-header")
			end
			f.r:htmlDivBegin("message")
			local time = os.date("%Y/%m/%d %H:%M:%S", message.time)
			local fromto
			if from then fromto = "from" else fromto = "to" end
			header(fromto, string.format("%s (%s)", alias, time))
			header("subject", message.subject)
			f.r:htmlDivBegin("message-body", { style = { color = color } })
			f.r:pe(message.body)
			f.r:htmlDivEnd("message-body")
			f.r:htmlDivEnd("message")
			f.r:emptyl("a", { name = "message_" .. i })
		end
		f.r:htmlDivEnd("messages")
		f.r:emptyl("a", { name = "end" })
		f.r:endl("body")
		f.r:htmlEnd()
		f:close()
		self.plugin.stoicheia.gui.pagewin:exec(string.format("setLocation(\"messages\", \"file://%s?%d#end\");", f.path, os.time()))
	end
}


